﻿namespace FunctionalProgramming.LazyCollections
{
   /// <summary>
   /// Instances of this class are used as return values of evaluation function.
   /// </summary>
   /// <typeparam name="T">Type of elements in resulting collection.</typeparam>
   /// <typeparam name="TEval">Type of data that will be evaluated.</typeparam>
   public class Option<T, TEval>
   {
      /// <summary>
      /// Gets a value indicating whether the value of the Current property should be added to the collection, or not.
      /// </summary>
      /// <value>
      ///   <c>true</c> if the value of the Current property should be added to the collection; otherwise, the end of collection is
      /// signalled and <c>false</c> is returned.
      /// </value>
      public bool AddCurrent { get; internal set; }

      /// <summary>
      /// Gets the value of element that should be added to the collection.
      /// </summary>
      public T Current { get; internal set; }

      /// <summary>
      /// Gets the next value for evaluation function.
      /// </summary>
      public TEval NextEvaluatorValue { get; internal set; }
   }

   /// <summary>
   /// Encapsulates creating of Option type instances.
   /// </summary>
   public static class Option
   {
      /// <summary>
      /// Returns instance that signals the collection still has some elements.
      /// </summary>
      /// <typeparam name="T">Type of elements in resulting collection.</typeparam>
      /// <typeparam name="TEval">Type of data that will be evaluated.</typeparam>
      /// <param name="current">The value of element that should be added to the collection.</param>
      /// <param name="nextEvaluatorValue">The next value for evaluation function.</param>
      /// <returns>Instance that signals the collection still has some elements.</returns>
      public static Option<T, TEval> Some<T, TEval>(T current, TEval nextEvaluatorValue)
      {
         return new Option<T, TEval> { AddCurrent = true, Current = current, NextEvaluatorValue = nextEvaluatorValue };
      }

      /// <summary>
      /// Returns instance that signals the collection has no more elements.
      /// </summary>
      /// <typeparam name="T">Type of elements in resulting collection.</typeparam>
      /// <typeparam name="TEval">Type of data that will be evaluated.</typeparam>
      /// <returns>Instance that signals the collection has no more elements.</returns>
      public static Option<T, TEval> None<T, TEval>()
      {
         return new Option<T, TEval> { AddCurrent = false };
      }
   }
}